// Kokomi.js - Three.js 组件框架
import * as kokomi from "kokomi.js";
// Three.js - 3D 渲染引擎
import * as THREE from "three";
// GSAP - 动画库，用于平滑过渡
import gsap from "gsap";
// Simplex Noise - 用于生成自然的随机噪声
import { createNoise2D } from "simplex-noise";

import type Experience from "../Experience";

// 创建 2D Simplex 噪声生成器（用于生成平滑的随机值）
const noise2d = createNoise2D();

/**
 * FBM (Fractional Brownian Motion) - 分形布朗运动
 * 通过叠加多层噪声生成更自然、更复杂的随机值
 * @param octave - 叠加层数（越多越细腻）
 * @param frequency - 频率（控制噪声变化快慢）
 * @param amplitude - 振幅（控制噪声强度）
 * @param lacunarity - 间隙度（每层频率的倍增系数，默认2倍）
 * @param persistance - 持续度（每层振幅的衰减系数，默认0.5倍）
 */
const fbm = ({
  octave = 3,
  frequency = 2,
  amplitude = 0.5,
  lacunarity = 2,
  persistance = 0.5,
} = {}) => {
  let value = 0;
  // 循环叠加多层噪声
  for (let i = 0; i < octave; i++) {
    const noiseValue = noise2d(frequency, frequency);
    value += noiseValue * amplitude;
    frequency *= lacunarity; // 频率倍增（细节更密集）
    amplitude *= persistance; // 振幅衰减（影响逐渐减弱）
  }
  return value;
};

// 相机抖动配置接口
export interface CameraShakeConfig {
  intensity: number; // 抖动强度（0-1，值越大抖动越强）
}

/**
 * 相机抖动组件
 * 用于模拟车辆加速时的相机晃动效果
 * 使用 Simplex 噪声 + FBM 算法生成自然的随机抖动
 */
export default class CameraShake extends kokomi.Component {
  declare base: Experience; // Experience 实例引用
  tweenedPosOffset: THREE.Vector3; // 平滑过渡后的位置偏移
  intensity: number; // 抖动强度
  
  constructor(base: Experience, config: Partial<CameraShakeConfig> = {}) {
    super(base);

    // 从配置中获取抖动强度，默认为 1
    const { intensity = 1 } = config;
    this.intensity = intensity;

    // 初始化位置偏移向量（用于 GSAP 平滑插值）
    const tweenedPosOffset = new THREE.Vector3(0, 0, 0);
    this.tweenedPosOffset = tweenedPosOffset;
  }
  /**
   * 每帧更新相机抖动
   * 由 Kokomi.js 框架自动调用
   */
  update(): void {
    // 获取经过的时间（秒）
    const t = this.base.clock.elapsedTime;
    
    // 生成三维随机位置偏移（X, Y, Z 轴）
    const posOffset = new THREE.Vector3(
      // X 轴偏移：使用时间 + 随机种子生成噪声
      fbm({
        frequency: t * 0.5 + THREE.MathUtils.randFloat(-10000, 0),
        amplitude: 2,
      }),
      // Y 轴偏移（上下抖动）
      fbm({
        frequency: t * 0.5 + THREE.MathUtils.randFloat(-10000, 0),
        amplitude: 2,
      }),
      // Z 轴偏移（前后抖动）
      fbm({
        frequency: t * 0.5 + THREE.MathUtils.randFloat(-10000, 0),
        amplitude: 2,
      })
    );
    
    // 缩放偏移量：0.1 是基础系数，乘以抖动强度
    posOffset.multiplyScalar(0.1 * this.intensity);
    
    // 使用 GSAP 平滑过渡到目标偏移（避免抖动过于生硬）
    gsap.to(this.tweenedPosOffset, {
      x: posOffset.x,
      y: posOffset.y,
      z: posOffset.z,
      duration: 1.2, // 1.2秒过渡时间
    });
    
    // 将偏移量应用到相机位置
    this.base.camera.position.add(this.tweenedPosOffset);
  }
  /**
   * 设置抖动强度
   * @param value - 强度值（0=无抖动，1=正常抖动，>1=强烈抖动）
   * 在 World.ts 的 rush() 方法中被调用
   */
  setIntensity(value: number) {
    this.intensity = value;
  }
}
